/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package clasesJXTA;

import compumundohipermegared.Foto;
import java.io.File;
import java.io.Serializable;
import java.net.InetAddress;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.Observable;
import net.jxta.discovery.DiscoveryEvent;
import net.jxta.discovery.DiscoveryListener;
import net.jxta.discovery.DiscoveryService;
import net.jxta.document.Advertisement;
import net.jxta.document.AdvertisementFactory;
import net.jxta.id.ID;
import net.jxta.id.IDFactory;
import net.jxta.impl.id.UUID.PipeID;
import net.jxta.peergroup.PeerGroup;
import net.jxta.peergroup.PeerGroupID;
import net.jxta.pipe.PipeService;
import net.jxta.platform.NetworkManager;
import net.jxta.protocol.PipeAdvertisement;

/**
 *
 * @author alvar-go@uniandes.edu.co
 */
public class AdministradorJXTA extends Observable implements DiscoveryListener, Serializable
{
    /**
     * Indicador de versión para la serialización
     */
    private static final long serialVersionUID = 210L;
    
    private static String RUTA_CACHE = "./data/cache";

    private NetworkManager manager;

    private PeerGroup netPeerGroup;

    private DiscoveryService discovery;

    private PipeAdvertisement pipeAdv;
    
    private PipeAdvertisement propagatePipeAdv;

    private String nombreNodo;

    public AdministradorJXTA(String nombre) throws Exception
    {
        nombreNodo = nombre;
        try 
        {
            manager = new NetworkManager( NetworkManager.ConfigMode.ADHOC, nombre, new File( getRUTA_CACHE(), nombre ).toURI( ) );
            manager.startNetwork( );
            
            //Registrar advertisements
            AdvertisementFactory.registerAdvertisementInstance( AdvertisementRecurso.getAdvertisementType( ), new MyAdvertisementRecurso.Instantiator( ) );

            netPeerGroup = manager.getNetPeerGroup( );
            PeerGroupID id = netPeerGroup.getPeerGroupID( );
            PipeID idPipe = crearPipeID( id );
            PipeID proIdPipe = crearPipeIDEstatico( id );
            pipeAdv = crearPipeAdvertisement( idPipe );
            propagatePipeAdv = crearPropagatePipeAdvertisement( proIdPipe );
            discovery = netPeerGroup.getDiscoveryService( );
            discovery.addDiscoveryListener( this );
        } 
        catch( Exception e )
        {
            e.printStackTrace();
            throw new Exception("no fue posible conectarse a la red: \n" + e.getMessage());
            
        }  
     }

     private static PipeID crearPipeID( PeerGroupID pgID )
     {
        PipeID socketID = null;
        try 
        {
            socketID = ( PipeID )IDFactory.newPipeID( pgID );
           
        } 
        catch( Exception ex )
        {

        }
        return socketID;
    }
     
     private static PipeID crearPipeIDEstatico(PeerGroupID pgID){
         PipeID socketID = null;
         byte[] semilla = new byte[4];
         semilla[0]=0;
         semilla[1]=0;
         semilla[2]=0;
         semilla[3]=0;
         
        try 
        {
            socketID = ( PipeID )IDFactory.newPipeID( pgID, semilla);
           
        } 
        catch( Exception ex )
        {

        }
        return socketID;
     }

    private PipeAdvertisement crearPipeAdvertisement( ID pipeId )
    {
        PipeAdvertisement advertisement = ( PipeAdvertisement )AdvertisementFactory.newAdvertisement( PipeAdvertisement.getAdvertisementType( ) );
        advertisement.setPipeID( pipeId );
        advertisement.setType( PipeService.UnicastType );
        advertisement.setName( nombreNodo );
        return advertisement;
    }
    
        private PipeAdvertisement crearPropagatePipeAdvertisement( ID pipeId )
    {
        PipeAdvertisement advertisement = ( PipeAdvertisement )AdvertisementFactory.newAdvertisement( PipeAdvertisement.getAdvertisementType( ) );
        advertisement.setPipeID( pipeId );
        advertisement.setType( PipeService.PropagateType );
        advertisement.setName( "Multicast" );
       
        return advertisement;
    }

    public void buscarPorID( String nID )
    {
        getDiscovery().getRemoteAdvertisements( null, DiscoveryService.ADV, MyAdvertisementRecurso.nombreAdvertisementTag, nID, 10, this );
    }
    
    public void buscarPorPersonas( String nPersonas )
    {
        getDiscovery().getRemoteAdvertisements( null, DiscoveryService.ADV, MyAdvertisementRecurso.personasTag, "*" + nPersonas + "*", 10, this );
    }

    public void publicarFoto( Foto foto )throws Exception
    {
        try
        {
            MyAdvertisementRecurso adv = new MyAdvertisementRecurso( );
            adv.setNombreAdvertisement( foto.getId( ) );
            String direccionIp = InetAddress.getLocalHost( ).getHostAddress( ).toString( );
            adv.setDireccionIP( direccionIp );
            adv.setNombreNodo( getNombreNodo());
            adv.setPersonasFoto( foto.getPersonas( ) );
            adv.setPipeAdv( getPipeAdv());
            getDiscovery().publish( adv );
        } 
        catch( Exception e ) 
        {
            throw new Exception( "No se pudó publicar la información del nodo en la red: \n" + e.getMessage( ) );
        }
    }

    public void deneterJXTA( )
    {
        getManager().stopNetwork( );
    }

    public void discoveryEvent( DiscoveryEvent de )
    {
        Enumeration<Advertisement> respuestas = de.getSearchResults( );
        ArrayList<NodoRemoto> nodosEncontrados = new ArrayList<NodoRemoto>( );
        
        while( respuestas.hasMoreElements( ) )
        {
            Object advertisement = respuestas.nextElement( );
            if( advertisement instanceof MyAdvertisementRecurso )
            {
                MyAdvertisementRecurso ad = ( MyAdvertisementRecurso )advertisement;
                if( !ad.getNombreNodo( ).equals( nombreNodo ) )
                {   
                    NodoRemoto nr = new NodoRemoto( ad.getDireccionIP( ), ad.getNombreNodo( ), ad.getNombreAdvertisement( ), ad.getPipeAdv() );
                    nodosEncontrados.add( nr );
                }
            }
        }

        setChanged( );
        notifyObservers( nodosEncontrados );
    }

    /**
     * @return the RUTA_CACHE
     */
    public static String getRUTA_CACHE() {
        return RUTA_CACHE;
    }

    /**
     * @param aRUTA_CACHE the RUTA_CACHE to set
     */
    public static void setRUTA_CACHE(String aRUTA_CACHE) {
        RUTA_CACHE = aRUTA_CACHE;
    }

    /**
     * @return the manager
     */
    public NetworkManager getManager() {
        return manager;
    }

    /**
     * @param manager the manager to set
     */
    public void setManager(NetworkManager manager) {
        this.manager = manager;
    }

    /**
     * @return the netPeerGroup
     */
    public PeerGroup getNetPeerGroup() {
        return netPeerGroup;
    }

    /**
     * @param netPeerGroup the netPeerGroup to set
     */
    public void setNetPeerGroup(PeerGroup netPeerGroup) {
        this.netPeerGroup = netPeerGroup;
    }

    /**
     * @return the discovery
     */
    public DiscoveryService getDiscovery() {
        return discovery;
    }

    /**
     * @param discovery the discovery to set
     */
    public void setDiscovery(DiscoveryService discovery) {
        this.discovery = discovery;
    }

    /**
     * @return the pipeAdv
     */
    public PipeAdvertisement getPipeAdv() {
        return pipeAdv;
    }

    /**
     * @param pipeAdv the pipeAdv to set
     */
    public void setPipeAdv(PipeAdvertisement pipeAdv) {
        this.pipeAdv = pipeAdv;
    }

    /**
     * @return the nombreNodo
     */
    public String getNombreNodo() {
        return nombreNodo;
    }

    /**
     * @param nombreNodo the nombreNodo to set
     */
    public void setNombreNodo(String nombreNodo) {
        this.nombreNodo = nombreNodo;
    }
    
    public PipeAdvertisement getPropagatePipeAdv() 
    {
        return propagatePipeAdv;
    }
}